home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 501-525 / disk_512 / csh / csh515s.lzh / comm2.c < prev    next >
C/C++ Source or Header  |  1991-06-22  |  30KB  |  1,249 lines

  1. /*
  2.  * COMM2.C
  3.  *
  4.  * (c)1986 Matthew Dillon     9 October 1986
  5.  *
  6.  * Version 2.07M by Steve Drew 10-Sep-87
  7.  * Version 4.01A by Carlo Borreo & Cesare Dieni 17-Feb-90
  8.  * Version 5.00L by Urban Mueller 17-Feb-91
  9.  *
  10.  */
  11.  
  12. #include "shell.h"
  13.  
  14. /* comm2.c */
  15. static long dptrtosecs(struct DPTR *d);
  16. static long timeof(char *s);
  17. static int evalif(void);
  18. static int clinum(char *name);
  19. static int copydir(long srcdir, long destdir, int recur);
  20. static int copyfile(char *srcname, long srcdir, char *destname, long destdir);
  21. static int file_date(struct DateStamp *date, char *name);
  22. static void changedisk(struct MsgPort *task);
  23. static int func_array( char *fav[], int fac);
  24. static int func_int(int i);
  25. static int func_bool(int i);
  26. static int func_string(char *str);
  27. static int commas(char *av[], int ac, int n);
  28. static int wordset(char **av, int ac, char **(*func)(char **,int,char**,int,int*,int));
  29. static int split_arg(char **av, int ac);
  30. static char *info_part(char **av, int ac, int n, char *buf);
  31.  
  32. /* Casting conveniences */
  33. #define BPTR_TO_C(strtag, var)  ((struct strtag *)(BADDR( (ULONG) var)))
  34. #define PROC(task)              ((struct Process *)task)
  35. #define CLI(proc)               (BPTR_TO_C(CommandLineInterface, proc->pr_CLI))
  36.  
  37. /* Externs */
  38. extern int has_wild;                    /* flag set if any arg has a ? or * */
  39.  
  40. /* globals */
  41. static int cp_update, cp_date, cp_flags, cp_fresh, cp_move;
  42.  
  43. do_abortline( void )
  44. {
  45.     Exec_abortline = 1;
  46.     return 0;
  47. }
  48.  
  49. do_error( void )
  50. {
  51.     return atoi(av[1]);
  52. }
  53.  
  54. do_return( void )
  55. {
  56.     int retcode=(ac<2 ? 0 : atoi(av[1]));
  57.  
  58.     Exec_abortline = 1;
  59.     if (Src_stack) {
  60.         Src_abort[Src_stack-1]=1;
  61.         return retcode;
  62.     } else
  63.         main_exit(retcode);
  64.     return 0;
  65. }
  66.  
  67. /*
  68.  * STRHEAD
  69.  *
  70.  * place a string into a variable removing everything after and including
  71.  * the 'break' character
  72.  *
  73.  * strhead varname breakchar string
  74.  *
  75.  */
  76.  
  77. do_strhead( void )
  78. {
  79.     char *s;
  80.     if (*av[2] && (s=index( av[3], *av[2]))) 
  81.         *s='\0';
  82.     set_var (LEVEL_SET, av[1], av[3]);
  83.     return 0;
  84. }
  85.  
  86. do_strtail( void )
  87. {
  88.     char *s;
  89.     if (*av[2] && (s=index(av[3],*av[2]))) s++; else s=av[3];
  90.     set_var (LEVEL_SET, av[1], s);
  91.     return 0;
  92. }
  93.  
  94. static long
  95. dptrtosecs(struct DPTR *d)
  96. {
  97.     struct DateStamp *ds=(&d->fib->fib_Date);
  98.     return ds->ds_Days*86400 + ds->ds_Minute*60 + ds->ds_Tick/TICKS_PER_SECOND;
  99. }
  100.  
  101. static long
  102. timeof(char *s)
  103. {
  104.     struct DPTR *d;
  105.     int dummy;
  106.     long n;
  107.  
  108.     if ( (d=dopen(s,&dummy))==NULL ) return 0L;
  109.     n=dptrtosecs(d);
  110.     dclose(d);
  111.     return n;
  112. }
  113.  
  114. /*
  115.  * if -f file (exists) or:
  116.  *
  117.  * if A < B   <, >, =, <=, >=, <>, where A and B are either:
  118.  * nothing
  119.  * a string
  120.  * a value (begins w/ number)
  121.  */
  122.  
  123. #define IF_NOT 128
  124.  
  125. do_if( char *garbage, int com )
  126. {
  127.     int result;
  128.  
  129.     switch (com) {
  130.     case 0:
  131.         if (If_stack && If_base[If_stack - 1])
  132.             If_base[If_stack++] = 1;
  133.         else {
  134.             result=evalif();
  135.             If_base[If_stack++]=(options & IF_NOT ? result : !result);
  136.         }
  137.         break;
  138.     case 1:
  139.         if (If_stack > 1 && If_base[If_stack - 2]) break;
  140.         if (If_stack) If_base[If_stack - 1] ^= 1;
  141.         break;
  142.     case 2:
  143.         if (If_stack) --If_stack;
  144.         break;
  145.     }
  146.     disable = (If_stack) ? If_base[If_stack - 1] : 0;
  147.     if (If_stack >= MAXIF) {
  148.         fprintf(stderr,"If's too deep\n");
  149.         disable = If_stack = 0;
  150.         return -1;
  151.     }
  152.     if (forward_goto) disable = If_base[If_stack - 1] = 0;
  153.     return 0;
  154. }
  155.  
  156. static int
  157. isint( char *s )
  158. {
  159.     while( ISSPACE(*s) ) ++s;
  160.     return *s=='+' || *s=='-' || *s>='0' && *s<='9';
  161. }
  162.  
  163. static int
  164. evalif()
  165. {
  166.     char c, *str, *left, *right, *cmp;
  167.     long num, t0, i=1;
  168.     int nac=ac-1;
  169.  
  170.     switch(options & ~IF_NOT) {
  171.     case 0:
  172.         for( i=1; i<ac; i++ )
  173.             if( strlen(str=av[i])<=2 && *str && index("<=>",*str) &&
  174.                    (!str[1] || index("<=>",str[1])))
  175.                 break;
  176.  
  177.         if ( i==ac )
  178.             return ac>1 && *av[1] && strcmp(av[1],"0");
  179.  
  180.         left =av[1];
  181.         right=av[i+1];
  182.         if( 1+1!=i )    left = compile_av(av,1,i   ,0xA0, 0);
  183.         if( i+1+1!=ac ) right= compile_av(av,i+1,ac,0xA0, 0);
  184.         cmp  = av[i];
  185.         num  = Atol(left) - Atol(right);
  186.         if (!isint(left) || !isint(right)) num=strcmp(left,right);
  187.         if( 1+1!=i )    free(left); 
  188.         if( i+1+1!=ac ) free(right);
  189.  
  190.         if (num < 0)       c='<';
  191.         else if (num > 0)  c='>';
  192.         else               c='=';
  193.         return index(cmp, c) != NULL;
  194.     case 1:
  195.         return do_rpn(NULL,i);
  196.     case 2:
  197.         return exists(av[i]);
  198.     case 4:
  199.         t0=timeof(av[i++]);
  200.         for ( ; i<ac ; i++)
  201.             if (t0<=timeof(av[i])) return 1;
  202.         return 0;
  203.     case 8:
  204.         return AvailMem( MEMF_FAST )!=0;
  205.     case 16:
  206.         return isdir(av[i])!=0;
  207.     case 32:
  208.         return get_var(LEVEL_SET,av[i]) != 0;
  209.     case 64:
  210.         return ac>1 ? get_opt(av+1,&nac,-*av[1]) : 0;
  211.     default:
  212.         ierror(NULL,500);
  213.     }
  214.     return 0;
  215. }
  216.  
  217. #if 0
  218. do_while( void )
  219. {
  220.     char *com=av[--ac];
  221.     int ret=0;
  222.  
  223.     while( evalif() && ret==0 && !CHECKBREAK() )
  224.         ret=execute( com );
  225.     return ret;
  226. }
  227. #endif
  228.  
  229.  
  230. do_label( void )
  231. {
  232.     char aseek[32];
  233.  
  234.     if (Src_stack == 0) {
  235.         ierror (NULL, 502);
  236.         return -1;
  237.     }
  238.  
  239.     sprintf (aseek, "%ld %d", Src_pos[Src_stack-1], If_stack);
  240.     set_var (LEVEL_LABEL + Src_stack - 1, av[1], aseek);
  241.     if (!strcmp(av[1],get_var(LEVEL_SET,v_gotofwd)))
  242.         forward_goto = 0;
  243.     return 0;
  244. }
  245.  
  246. do_goto( void )
  247. {
  248.     int new;
  249.     long pos;
  250.     char *lab;
  251.  
  252.     if (Src_stack == 0) {
  253.         ierror (NULL, 502);
  254.     } else {
  255.         lab = get_var (LEVEL_LABEL + Src_stack - 1, av[1]);
  256.         if (lab == NULL) {
  257.             forward_goto = 1;
  258.             set_var (LEVEL_SET, v_gotofwd, av[1]);
  259.             return(0);
  260.         } else {
  261.             pos = atoi(lab);
  262.             fseek (Src_base[Src_stack - 1], pos, 0);
  263.             Src_pos[Src_stack - 1] = pos;
  264.             new = atoi(next_word(lab));
  265.             for (; If_stack < new; ++If_stack)
  266.                 If_base[If_stack] = 0;
  267.             If_stack = new;
  268.         }
  269.     }
  270.     Exec_abortline = 1;
  271.     return (0);      /* Don't execute rest of this line */
  272. }
  273.  
  274.  
  275. do_inc(char *garbage, int com)
  276. {
  277.     char *var, num[32];
  278.  
  279.     if (ac>2) com *= atoi(av[2]);
  280.     if (var = get_var (LEVEL_SET, av[1])) {
  281.         sprintf (num, "%d", atoi(var)+com);
  282.         set_var (LEVEL_SET, av[1], num);
  283.     }
  284.     return 0;
  285. }
  286.  
  287. BPTR Input(void);
  288. BPTR Output(void);
  289.  
  290. do_input( void )
  291. {
  292.     char *str, in[256], *get, *put;
  293.     int i, quote=0;
  294.  
  295.     if( options&2 ) {
  296.         if( !isconsole(Input()) ) return 20;
  297.         setrawcon( -1, 0 );
  298.         in[1]=0;
  299.         for ( i=1; i<ac; ++i) {
  300.             in[0]=getchar();
  301.             set_var (LEVEL_SET, av[i], in);
  302.         }
  303.         setrawcon( 2, 0 );
  304.         return 0;
  305.     }
  306.  
  307.     for ( i=1; i<ac; ++i)
  308.         if (fgets(in,256,stdin)) {
  309.             str=in, put=in+strlen(in)-1;
  310.             if( *put=='\n' ) *put=0;
  311.             if( !(options&1) ) {
  312.                 while( *str==' ' ) str++;
  313.                 for( put=get=str; *get; ) {
  314.                     if( *get=='\"' )
  315.                         quote=1-quote, get++;
  316.                     else if( *get==' ' && !quote ) {
  317.                         while( *get==' ' ) get++;
  318.                         if( *get ) *put++=0xA0;
  319.                     } else 
  320.                         *put++=*get++;
  321.                 }
  322.                 *put=0;
  323.             }
  324.             set_var (LEVEL_SET, av[i], str);
  325.         }
  326.     return 0;
  327. }
  328.  
  329. do_ver( void )
  330. {
  331.     extern char shellname[];
  332.  
  333.     puts(shellname);
  334.     puts("1.00 Lattice (c) 1986 Matthew Dillon\n"
  335.          "2.05 Manx(M) versions by Steve Drew\n"
  336.          "3.00 ARP (A) versions by Carlo Borreo, Cesare Dieni\n"
  337.          "4.00 ARP 1.3 versions by Carlo Borreo, Cesare Dieni\n"
  338.          "5.00 Lattice versions by U. Dominik Mueller (umueller@iiic.ethz.ch)\n");
  339.     printf("Compiled: "__DATE__" "__TIME__" with "COMPILER"\n" );
  340.     return 0;
  341. }
  342.  
  343.  
  344. static int
  345. clinum( char *name )
  346. {
  347.     int ncli=(long)FindCLI(0L), count;
  348.     struct Task *task;
  349.     char cmd[40+1];
  350.  
  351.     if( *name>='0' && *name<='9' )
  352.         return atoi( name );
  353.  
  354.     Forbid();
  355.     for (count = 1; count <= ncli ; count++)
  356.         if (task = (struct Task *)FindCLI(count)) {
  357.             if ( !PROC(task)->pr_TaskNum || PROC(task)->pr_CLI == 0) continue;
  358.             BtoCStr(cmd,   CLI(PROC(task))->cli_CommandName, 40L);
  359.             if( !Strcmp( BaseName( cmd ), name ))
  360.                 goto done;
  361.         }
  362.     count=-1;
  363. done:
  364.     Permit();
  365.     return count;
  366. }
  367.  
  368. do_ps( void )
  369. {
  370.     /* this code fragment based on ps.c command by Dewi Williams */
  371.     int count;             /* loop variable         */
  372.     struct Task *task;     /* EXEC descriptor       */
  373.     char strbuf[64+1];     /* scratch for btocstr() */
  374.     char cmd[40+1], *com;  /* holds cmd name        */
  375.     long ncli,mycli,cli,i;
  376.  
  377.     char onoff[80];
  378.     memset( onoff, 0, 80 );
  379.     for( i=1; i<ac; i++ )
  380.         onoff[ 1+clinum( av[i] ) ]=1;
  381.     if( options&2 )
  382.         for( i=0; i<80; i++ )
  383.             onoff[i]=1-onoff[i];
  384.  
  385.     printf("Proc Command Name         CLI Type    Pri.  Address  Directory\n");
  386.     Forbid();
  387.  
  388.     ncli=(long)FindCLI(0L);
  389.     mycli= Myprocess->pr_TaskNum;
  390.     for (count = 1; count <= ncli ; count++)             /* or just assume 20?*/
  391.         if (task = (struct Task *)FindCLI((long)count)) {/* Sanity check      */
  392.             cli=PROC(task)->pr_TaskNum;
  393.             if( ac>1 && !onoff[1+cli] )
  394.                 continue;
  395.             if ( cli==0 || PROC(task)->pr_CLI == 0) continue; /* or complain? */
  396.                 BtoCStr(cmd,   CLI(PROC(task))->cli_CommandName, 40L);
  397.                 BtoCStr(strbuf,CLI(PROC(task))->cli_SetName    , 64L);
  398.             com=cmd;
  399.             if( !(options&1) )
  400.                 com=BaseName(com);
  401.             printf("%c%2d  %-20.20s %-11.11s %3d  %8lx  %s\n",
  402.                 cli==mycli ? '*' : ' ',
  403.                 count,
  404.                 com,
  405.                 task->tc_Node.ln_Name,
  406.                 (signed char)task->tc_Node.ln_Pri,
  407.                 task,
  408.                 strbuf
  409.             );
  410.         }
  411.  
  412.     Permit();
  413.     return 0;
  414. }
  415.  
  416. /*
  417.  * CP [-d] [-u] file file
  418.  * CP [-d] [-u] file file file... destdir
  419.  * CP [-r][-u][-d] dir dir dir... destdir
  420.  */
  421.  
  422. char *errstr;          /* let's be alittle more informative */
  423.  
  424. do_copy( void )
  425. {
  426.     int recur, ierr;
  427.     char *destname;
  428.     char destisdir;
  429.     FIB *fib;
  430.     int i=1;
  431.  
  432.     errstr = "";
  433.     ierr = 0;
  434.  
  435.     fib = (FIB *)SAllocMem((long)sizeof(FIB), MEMF_PUBLIC);
  436.  
  437.     recur     = (options & 0x01);
  438.     cp_update = (options & 0x02);
  439.     cp_date   =!(options & 0x04); /* the default is keep orignal file date */
  440.     cp_flags  =!(options & 0x08);
  441.     cp_fresh  = (options & 0x10);
  442.     cp_move   = (options & 0x20);
  443.  
  444.     destname = av[ac - 1];
  445.  
  446.     if (ac < i + 2) {
  447.         ierr = 500;
  448.         goto done;
  449.     }
  450.     destisdir = isdir(destname);
  451.     if (ac > i + 2 && !destisdir) {
  452.         ierr = 507;
  453.         goto done;
  454.     }
  455.  
  456. /*
  457.  * copy set:                        reduce to:
  458.  *    file to file                     file to file
  459.  *    dir  to file (NOT ALLOWED)
  460.  *    file to dir                      dir to dir
  461.  *    dir  to dir                      dir to dir
  462.  *
  463.  */
  464.  
  465.     for (; i<ac-1 && !dobreak(); ++i) {
  466.         short srcisdir = isdir(av[i]);
  467.         if (srcisdir && has_wild && (ac >2)) /* hack to stop dir's from */
  468.             continue;                    /* getting copied if specified */
  469.                                          /* from wild expansion         */
  470.         if (srcisdir) {
  471.             BPTR srcdir, destdir;
  472.             if (!destisdir) {
  473.                 if (exists(destname)) {
  474.                     ierr = 507;    /* disallow dir to file */
  475.                     goto done;
  476.                     }
  477.                 if (destdir = CreateDir(destname)) UnLock(destdir);
  478.                 destisdir = 1;
  479.             }
  480.             if (!(destdir = Lock(destname, ACCESS_READ))) {
  481.                 ierr = 205;
  482.                 errstr = destname;
  483.                 goto done;
  484.             }
  485.             if (!(srcdir = Lock(av[i], ACCESS_READ))) {
  486.                 ierr = 205;
  487.                 errstr = av[i];
  488.                 UnLock(destdir);
  489.                 goto done;
  490.             }
  491.             ierr = copydir(srcdir, destdir, recur);
  492.             UnLock(srcdir);
  493.             UnLock(destdir);
  494.             if (ierr) break;
  495.         } else {                   /* FILE to DIR,   FILE to FILE   */
  496.             BPTR destdir, srcdir, tmp;
  497.             char *destfilename;
  498.  
  499.             srcdir = (BPTR)(Myprocess->pr_CurrentDir);
  500.  
  501.             if ((tmp = Lock(av[i], ACCESS_READ)) == NULL || !Examine(tmp,fib)) {
  502.                 if (tmp) UnLock(tmp);
  503.                 ierr = 205;
  504.                 errstr = av[i];
  505.                 goto done;
  506.             }
  507.             UnLock(tmp);
  508.             if (destisdir) {
  509.                 destdir = Lock(destname, ACCESS_READ);
  510.                 destfilename = fib->fib_FileName;
  511.             } else {
  512.                 destdir = srcdir;
  513.                 destfilename = destname;
  514.             }
  515.             printf(" %s..",av[i]);
  516.             fflush(stdout);
  517.             ierr = copyfile(av[i], srcdir, destfilename, destdir);
  518.             if (destisdir) UnLock(destdir);
  519.             if (ierr) break;
  520.         }
  521.     }
  522.  
  523. done:
  524.  
  525.     FreeMem(fib, (long)sizeof(FIB));
  526.     if (ierr) {
  527.         ierror(errstr, ierr);
  528.         return(20);
  529.     }
  530.     return 0;
  531. }
  532.  
  533. static int
  534. copydir(BPTR srcdir, BPTR destdir, int recur)
  535. {
  536.     static int level;
  537.     BPTR cwd;
  538.     FIB *srcfib;
  539.     BPTR destlock, srclock;
  540.     int ierr=0;
  541.  
  542.     level++;
  543.  
  544.     srcfib = (FIB *)SAllocMem((long)sizeof(FIB), MEMF_PUBLIC);
  545.     if( !Examine(srcdir, srcfib)) {
  546.         ierr=IoErr();
  547.         goto done;
  548.     }
  549.  
  550.     while (ExNext(srcdir, srcfib)) {
  551.         if (CHECKBREAK())
  552.             break;
  553.         if (srcfib->fib_DirEntryType < 0) {
  554.             printf("%*s%s..",(level-1) * 6," ",srcfib->fib_FileName);
  555.             fflush(stdout);
  556.             ierr = copyfile(srcfib->fib_FileName,srcdir,srcfib->fib_FileName,destdir);
  557.             if (ierr) break;
  558.         } else {
  559.             if ( srcfib->fib_DirEntryType!=ST_USERDIR ) {
  560.                 printf("%*s%s (Dir)....[Skipped. Is a link]\n",(level-1) * 6,
  561.                                " ",srcfib->fib_FileName);
  562.                 continue;
  563.             }
  564.             if (recur) {
  565.                 cwd = CurrentDir(srcdir);
  566.                 if (srclock = Lock(srcfib->fib_FileName, ACCESS_READ)) {
  567.                     CurrentDir(destdir);
  568.                     if (!(destlock = Lock(srcfib->fib_FileName,ACCESS_READ))) {
  569.                         destlock = CreateDir(srcfib->fib_FileName);
  570.                         printf("%*s%s (Dir)....[Created]\n",(level-1) * 6,
  571.                                " ",srcfib->fib_FileName);
  572.  
  573.                         /* UnLock and re Lock if newly created
  574.                          * for file_date() to work properly */
  575.                         if (destlock)
  576.                             UnLock(destlock);
  577.                         destlock = Lock(srcfib->fib_FileName, ACCESS_READ);
  578.                     } else
  579.                         printf("%*s%s (Dir)\n",(level-1) * 6," ",srcfib->fib_FileName);
  580.                     if (destlock) {
  581.                         ierr = copydir(srclock, destlock, recur);
  582.                         UnLock(destlock);
  583.                     } else {
  584.                         ierr = (int)((long)IoErr());
  585.                     }
  586.                     UnLock(srclock);
  587.                 } else {
  588.                     ierr = (int)((long)IoErr());
  589.                 }
  590.                 CurrentDir(cwd);
  591.                 if (ierr)
  592.                     break;
  593.             }
  594.         }
  595.     }
  596. done:
  597.     --level;
  598.     FreeMem(srcfib, (long)sizeof(FIB));
  599.     return(ierr);
  600. }
  601.  
  602. #define COPYBUF 32768
  603.  
  604. static int
  605. copyfile(char *srcname, BPTR srcdir, char *destname, BPTR destdir)
  606. {
  607.     BPTR cwd;
  608.     BPTR f1, f2;
  609.     long i;
  610.     int stat,ierr;
  611.     char *buf;
  612.     struct DPTR *dp, *dps;
  613.  
  614.     if ((buf = (char *)AllocMem(COPYBUF, MEMF_PUBLIC|MEMF_CLEAR))==NULL)
  615.         { ierr = 103; goto fail2; }
  616.     ierr = 0;
  617.     cwd = CurrentDir(srcdir);
  618.     if ((f1=Open(srcname, MODE_OLDFILE))==NULL)
  619.         { errstr = srcname; ierr = 205; goto fail; }
  620.     dps = dopen(srcname,&stat);
  621.     CurrentDir(destdir);
  622.     if (cp_update || cp_fresh) {
  623.         if( dp=dopen(destname, &stat) ) {
  624.             if ( dptrtosecs(dp) >= dptrtosecs(dps) &&
  625.                       !Strcmp(dps->fib->fib_FileName, dp->fib->fib_FileName))
  626.             { dclose(dp); Close(f1); printf("..not newer\n"); goto fail; }
  627.             dclose(dp);
  628.         } else if( cp_fresh ) {
  629.             Close(f1); printf("..not there\n"); goto fail;
  630.         }
  631.     }
  632.     if ((f2=Open(destname, MODE_NEWFILE))==NULL)
  633.         { Close(f1); ierr = (int)((long)IoErr()); errstr=destname; goto fail;  }
  634.     while (i = Read(f1, buf, COPYBUF))
  635.         if( dobreak() )
  636.             { ierr=513; break; }
  637.         else if (Write(f2, buf, i) != i)
  638.             { ierr = IoErr(); break; }
  639.     Close(f2);
  640.     Close(f1);
  641.     if (!ierr) {
  642.         if (cp_date) file_date(&dps->fib->fib_Date, destname);
  643.         if (cp_flags ) {
  644.             SetProtection( destname, dps->fib->fib_Protection&~FIBF_ARCHIVE);
  645.             if( *dps->fib->fib_Comment )
  646.                 SetComment( destname, dps->fib->fib_Comment );
  647.         }
  648.         dclose(dps); dps=NULL;
  649.         if( cp_move ) {
  650.             CurrentDir(srcdir);
  651.             DeleteFile(srcname);
  652.             printf("..moved\n");
  653.         } else
  654.             printf("..copied\n");
  655.     } else {
  656.         DeleteFile(destname);
  657.     }
  658. fail:
  659.     if( dps ) dclose(dps);
  660.     if (buf) FreeMem(buf, COPYBUF);
  661.     CurrentDir(cwd);
  662. fail2:
  663.     return(ierr);
  664. }
  665.  
  666. do_touch( void )
  667. {
  668.     struct DateStamp ds;
  669.     int i;
  670.     DateStamp(&ds);
  671.     for (i=1; i<ac; i++)
  672.         if (file_date(&ds, av[i]))
  673.             ierror(av[i],500);
  674.         else 
  675.             clear_archive_bit( av[i] );
  676.     return 0;
  677. }
  678.  
  679.  
  680. static int
  681. file_date( struct DateStamp *date, char *name )
  682. {
  683.     long packargs[7];
  684.     struct MsgPort *task;
  685.     struct DPTR *tmp;
  686.     BPTR dirlock;
  687.     char *ptr;
  688.     int stat;
  689.  
  690.     if (!(task = (struct MsgPort *)DeviceProc(name))) return(1);
  691.     if (tmp = dopen(name, &stat)) {
  692.         dirlock = ParentDir(tmp->lock);
  693.         ptr=SAllocMem(65L,MEMF_PUBLIC);
  694.         CtoBStr(tmp->fib->fib_FileName,(ULONG)ptr >> 2L,64L);
  695.         dclose(tmp);
  696.         packargs[1]=dirlock;
  697.         packargs[2]=(ULONG)ptr >> 2L;
  698.         packargs[3]=(long)date;
  699.         SendPacket(ACTION_SET_DATE,packargs,task);
  700.         UnLock(dirlock);
  701.         FreeMem(ptr,65L);
  702.     }
  703.     return 0;
  704. }
  705.  
  706. do_addbuffers( void )
  707. {
  708.     long packargs[7], i;
  709.     struct MsgPort *task;
  710.  
  711.     for( i=1; i<=ac-2; i+=2 ) {
  712.         if( i==ac-1 )
  713.             { ierror( av[i], 500 ); return 20; }
  714.         if( !(task=(struct MsgPort *)DeviceProc(av[i])))
  715.             { ierror(av[1],510); return 20; }
  716.         packargs[0]=myatoi(av[i+1],1,32767); if (atoierr) return 20;
  717.         SendPacket(ACTION_MORE_CACHE,packargs,task);
  718.     }
  719.     return 0;
  720. }
  721.  
  722. do_relabel( void )
  723. {
  724.     long packargs[7];
  725.     struct MsgPort *task=(struct MsgPort *)DeviceProc(av[1]);
  726.     char *ptr;
  727.  
  728.     if (!task) { ierror(av[1],510); return 20; }
  729.     ptr=SAllocMem(65L,MEMF_PUBLIC);
  730.     CtoBStr(av[2],(ULONG)ptr >> 2L,64L);
  731.     packargs[0]=(ULONG)ptr >> 2L;
  732.     SendPacket(ACTION_RENAME_DISK,packargs,task);
  733.     FreeMem(ptr,65L);
  734.     Delay(10);
  735.     changedisk(task);
  736.     return 0;
  737. }
  738.  
  739. do_diskchange( void )
  740. {
  741.     struct MsgPort *task=(struct MsgPort *)DeviceProc(av[1]);
  742.  
  743.     if (!task) { ierror(av[1],510); return 20; }
  744.     changedisk(task);
  745.     return 0;
  746. }
  747.  
  748. static void
  749. changedisk(struct MsgPort *task)
  750. {
  751.     long packargs[7];
  752.  
  753.     packargs[0]= DOSTRUE;
  754.     SendPacket(ACTION_INHIBIT,packargs,task);
  755.     packargs[0]= DOSFALSE;
  756.     SendPacket(ACTION_INHIBIT,packargs,task);
  757. }
  758.  
  759.  
  760. extern int atoierr;
  761.  
  762. static int
  763. func_array( char *fav[], int fac)
  764. {
  765.     char *ret;
  766.     if( atoierr ) return 20;
  767.     if( fac ) {
  768.         ret=compile_av( fav, 0, fac, 0xa0, 0);
  769.         set_var( LEVEL_SET, v_value, ret );
  770.         free( ret );
  771.     } else 
  772.         unset_var( LEVEL_SET, v_value );
  773.     return 0;
  774. }
  775.  
  776. static int
  777. func_int( int i )
  778. {
  779.     char buf[12];
  780.     if( atoierr ) return 20;
  781.     sprintf(buf,"%d",i);
  782.     set_var( LEVEL_SET, v_value, buf );
  783.     return 0;
  784. }
  785.  
  786. static int
  787. func_bool( int i )
  788. {
  789.     if( atoierr ) return 20;
  790.     set_var( LEVEL_SET, v_value, i ? "1" : "0" );
  791.     return 0;
  792. }
  793.  
  794. static int
  795. func_string( char *str )
  796. {
  797.     if( atoierr ) return 20;
  798.     set_var( LEVEL_SET, v_value, str ? str : "" );
  799.     return 0;
  800. }
  801.  
  802. static int
  803. commas( char *av[], int ac, int n )
  804. {
  805.     int i=0;
  806.  
  807.     while( --ac>=0 )
  808.         if( !strcmp( *av++, ",") )
  809.             i++;
  810.     if( i-=n )
  811.         fprintf( stderr, "Need %d comma%s\n", n, (n==1) ? "" : "s" );
  812.     return i;
  813. }
  814.  
  815. static int
  816. wordset( char *av[], int ac, char **(*func)(char **,int,char**,int,int*,int) )
  817. {
  818.     char **av1=av, **av2;
  819.     int  ac1=0, ac2, ret;
  820.  
  821.     if( commas( av, ac, 1 ) ) return 20;
  822.     while( strcmp( *av++, ",") ) ac1++;
  823.     av2=av, ac2=ac-ac1-1;
  824.     av=(*func)( av1, ac1, av2, ac2, &ac, 0 );
  825.     ret=func_array( av, ac );
  826.     free( av );
  827.     return ret;
  828. }
  829.  
  830. static int
  831. split_arg( char **av, int ac )
  832. {
  833.     char **arr, **old, *arg;
  834.     int i, j=1, ret;
  835.  
  836.     for( i=strlen(av[0])-1; i>=0; i-- )
  837.         if( av[0][i]==' ' )
  838.             av[0][i]=0, j++;
  839.  
  840.     arr=old=(char **)salloc( j*sizeof( char * ) );
  841.     arg=*av;
  842.     for( ; j>0; j-- ) {
  843.         *arr++=arg;
  844.         arg+=strlen(arg)+1;
  845.     }
  846.     ret=func_array( old, arr-old );
  847.     free(old);
  848.     return ret;
  849. }
  850.  
  851. static char *
  852. info_part( char **av, int ac, int n, char *buf )
  853. {
  854.     char *str;
  855.     struct DPTR *dp;
  856.     int len=0, i, t;
  857.  
  858.     buf[0]=0;
  859.     while( --ac>=0 ) {
  860.         if( dp=dopen( *av++, &t) ) {
  861.             if( n==0 ) {
  862.                 for (str=buf, i=7; i>=0; i--)
  863.                     *str++= (dp->fib->fib_Protection & (1L<<i) ?
  864.                             "hspa----" : "----rwed")[7-i];
  865.                 *str=0;
  866.             } else
  867.                 len+= dp->fib->fib_NumBlocks+1;
  868.             dclose( dp );
  869.         }
  870.     }
  871.     if( n ) sprintf(buf, "%d", len);
  872.     return buf;
  873. }
  874.  
  875. static struct FileRequester freq;
  876.  
  877. static char *
  878. file_request(char **av, int ac, char *path)
  879. {
  880.     struct FileRequester fr;
  881.     char filebuf[128];
  882.  
  883.     path[0]=0; filebuf[0]=0;
  884.     fr=freq; /* clear everything */
  885.     fr.fr_Hail="";
  886.     if( ac>0 ) {
  887.         fr.fr_Hail=av[0];
  888.         if( ac>1 ) {
  889.             strcpy( path,av[1]);
  890.             if( ac>2 )
  891.                 strcpy(filebuf,av[2]);
  892.         }
  893.     }
  894.     fr.fr_File  = filebuf;
  895.     fr.fr_Dir   = path;
  896.     fr.fr_Flags2= FR2F_LongPath;
  897.     if( !FileRequest( &fr ) )
  898.         return NULL;
  899.     TackOn( path,filebuf );
  900.     return path;
  901. }
  902.  
  903. int
  904. confirm( char *title, char *file )
  905. {
  906.     char buf[80];
  907.  
  908.     buf[0]=0;
  909.  
  910.     if( !confirmed ) {
  911.         fprintf(stderr,"%s %s%-16s%s [YES/no/all/done] ? ",
  912.                         title,o_hilite,file,o_lolite);
  913.         strupr(fgets(buf,80,stdin));
  914.         if( *buf=='A' )
  915.             confirmed=1;
  916.         if( *buf=='D' || breakcheck() )
  917.             confirmed=2;
  918.     }
  919.  
  920.     if( confirmed==2 )
  921.         return 0;
  922.     return confirmed || *buf != 'N';
  923. }
  924.  
  925. enum funcid {
  926.     FN_STUB=1, FN_MEMBER, FN_DIRS, FN_NAMEEXT, FN_NAMEROOT, FN_FILES,
  927.     FN_FILELEN, FN_SORTARGS, FN_UPPER, FN_WORDS, FN_ABBREV, FN_ABS,
  928.     FN_BINTODEC, FN_CENTER, FN_COMPARE, FN_DECTOHEX, FN_DELWORD,
  929.     FN_DELWORDS, FN_EXISTS, FN_INDEX, FN_STRCMP, FN_SUBWORDS,
  930.     FN_WORD, FN_MIN, FN_MAX, FN_DRIVES, FN_WITHOUT, FN_UNION, FN_INTERSECT,
  931.     FN_AVAILMEM, FN_UNIQUE, FN_RPN, FN_CONCAT, FN_SPLIT, FN_DRIVE,
  932.     FN_FILEPROT, FN_FILEBLKS, FN_LOWER, FN_HOWMANY, FN_COMPLETE, FN_FIRST,
  933.     FN_LAST, FN_MATCH, FN_CLINUM, FN_FREEBYTES, FN_FREEBLKS, FN_INFO,
  934.     FN_MEGS, FN_FREESTORE, FN_CHECKPORT, FN_PICKOPTS, FN_PICKARGS,
  935.     FN_FILEREQ, FN_VOLUME, FN_LOOKFOR, FN_APPSUFF, FN_PATHNAME, FN_AGE,
  936.     FN_GETCLASS, FN_CONFIRM, FN_WINWIDTH, FN_WINHEIGHT, FN_WINTOP,
  937.     FN_WINLEFT, FN_CONSOLE, FN_SORTNUM, FN_IOERROR, FN_TRIM, FN_MOUNTED,
  938. };
  939.  
  940. #define MAXAV        30000        /* Max. # of arguments            */
  941.  
  942. struct FUNCTION {
  943.     short id, minargs, maxargs;
  944.     char *name;
  945. } Function[]={
  946. FN_ABBREV,   2, 3,     "abbrev",
  947. FN_ABS,      1, 1,     "abs",
  948. FN_AGE,      1, 1,     "age",
  949. FN_APPSUFF,  2, 2,     "appsuff",
  950. FN_PICKARGS, 0, MAXAV, "arg",
  951. FN_AVAILMEM, 0, 1,     "availmem",
  952. FN_STUB,     1, 1,     "basename",
  953. FN_CENTER,   2, 2,     "center",
  954. FN_CHECKPORT,1, 1,     "checkport",
  955. FN_CLINUM,   1, 1,     "clinum",
  956. FN_COMPLETE, 1, MAXAV, "complete",
  957. FN_CONCAT,   0, MAXAV, "concat",
  958. FN_CONFIRM,  1, MAXAV, "confirm",
  959. FN_CONSOLE,  1, 1,     "console",
  960. FN_DECTOHEX, 1, 1,     "dectohex",
  961. FN_DELWORD,  1, MAXAV, "delword",
  962. FN_DELWORDS, 2, MAXAV, "delwords",
  963. FN_DIRS,     0, MAXAV, "dirs",
  964. FN_DRIVE,    1, 1,     "drive",
  965. FN_DRIVES,   0, 0,     "drives",
  966. FN_EXISTS,   1, 1,     "exists",
  967. FN_FILEBLKS, 1, MAXAV, "fileblks",
  968. FN_FILELEN,  0, MAXAV, "filelen",
  969. FN_FILEPROT, 1, 1,     "fileprot",
  970. FN_FILEREQ,  0, 3,     "filereq",
  971. FN_FILES,    0, MAXAV, "files",
  972. FN_FREEBLKS, 1, 1,     "freeblks",
  973. FN_FREEBYTES,1, 1,     "freebytes",
  974. FN_FREESTORE,1, 1,     "freestore",
  975. FN_FIRST,    0, MAXAV, "first",
  976. FN_STUB,     1, 1,     "getenv",
  977. FN_GETCLASS, 1, 1,     "getclass",
  978. FN_HOWMANY,  0, 0,     "howmany",
  979. FN_IOERROR,  1, 1,     "ioerr",
  980. FN_INDEX,    2, 2,     "index",
  981. FN_INFO,     1, 1,     "info",
  982. FN_INTERSECT,1, MAXAV, "intersect",
  983. FN_LAST,     0, MAXAV, "last",
  984. FN_LOOKFOR,  2, 2,     "lookfor",
  985. FN_LOWER,    0, MAXAV, "lower",
  986. FN_MATCH,    1, MAXAV, "match",
  987. FN_MAX,      1, MAXAV, "max",
  988. FN_MEGS,     1, 1,     "megs",
  989. FN_MEMBER,   1, MAXAV, "member",
  990. FN_MIN,      1, MAXAV, "min",
  991. FN_MOUNTED,  1, 1,     "mounted",
  992. FN_NAMEEXT,  1, 1,     "nameext",
  993. FN_NAMEROOT, 1, 1,     "nameroot",
  994. FN_PICKOPTS, 0, MAXAV, "opt",
  995. FN_PATHNAME, 1, 1,     "pathname",
  996. FN_PICKARGS, 0, MAXAV, "pickargs",
  997. FN_PICKOPTS, 0, MAXAV, "pickopts",
  998. FN_RPN,      1, MAXAV, "rpn",
  999. FN_SORTARGS, 0, MAXAV, "sortargs",
  1000. FN_SORTNUM,  0, MAXAV, "sortnum",
  1001. FN_SPLIT,    0, MAXAV, "split",
  1002. FN_STRCMP,   2, 2,     "strcmp",
  1003. FN_STUB,     2, 2,     "strhead",
  1004. FN_STUB,     2, 2,     "strleft",
  1005. FN_STUB,     2, 3,     "strmid",
  1006. FN_STUB,     2, 2,     "strright",
  1007. FN_STUB,     2, 2,     "strtail",
  1008. FN_SUBWORDS, 2, MAXAV, "subwords",
  1009. FN_STUB,     2, 2,     "tackon",
  1010. FN_TRIM,     0, MAXAV, "trim",
  1011. FN_UNION,    1, MAXAV, "union",
  1012. FN_UNIQUE,   0, MAXAV, "unique",
  1013. FN_UPPER,    0, MAXAV, "upper",
  1014. FN_VOLUME,   1, 1,     "volume",
  1015. FN_WINHEIGHT,0, 0,     "winheight",
  1016. FN_WINLEFT,  0, 0,     "winleft",
  1017. FN_WINTOP,   0, 0,     "wintop",
  1018. FN_WINWIDTH, 0, 0,     "winwidth",
  1019. FN_WITHOUT,  1, MAXAV, "without",
  1020. FN_WORD,     1, MAXAV, "word",
  1021. FN_WORDS,    0, MAXAV, "words",
  1022. 0,           0, NULL
  1023. };
  1024.  
  1025. extern char shellctr[];
  1026.  
  1027. int
  1028. dofunc( int id, char **av, int ac)
  1029. {
  1030.     char **oldav=av, **get=av, buf[200], *str=buf;
  1031.     int oldac=ac, i=0, j=0, n=0, n2=1, l;
  1032.     buf[0]=0;
  1033.     av[ac]=NULL;
  1034.  
  1035.     switch( id ) {
  1036.     case FN_ABBREV:
  1037.         if( ac==3 ) i=posatoi(av[2] ); else i=strlen(av[0]);
  1038.         return func_bool( !Strncmp( av[0], av[1], i ));
  1039.     case FN_ABS:
  1040.         i=unlatoi(av[0]);
  1041.         return func_int( i>= 0 ? i : -i );
  1042.     case FN_AGE: {
  1043.         struct DateStamp ds; long time;
  1044.         DateStamp( &ds ); if( ds.ds_Days==0 ) return 99999;
  1045.         if( !(time=timeof(av[0]))) return 99999;
  1046.         return func_int( (ds.ds_Days*86400+ds.ds_Minute*60-time)/86400 ); }
  1047.     case FN_APPSUFF:
  1048.         strcpy(buf,av[0]);
  1049.         l=strlen(av[0])-strlen(av[1]);
  1050.         if( l<0 || Strcmp(av[0]+l,av[1])) {
  1051.             strcat(buf,".");
  1052.             strcat(buf,av[1]);
  1053.         }
  1054.         return func_string( buf );
  1055.     case FN_AVAILMEM:
  1056.         if( ac==1 && !Strcmp(av[0],"chip")) n=MEMF_CHIP;
  1057.         if( ac==1 && !Strcmp(av[0],"fast")) n=MEMF_FAST;
  1058.         return func_int( AvailMem( n ));
  1059.     case FN_CENTER:
  1060.         if( (n=posatoi( av[1] )) > (l=strlen(av[0])) ) i=(n-l)/2, j=n-i-l;
  1061.         sprintf( buf, "%*s%s%*s", i,"",av[0], j,"" );
  1062.         return func_string( buf );
  1063.     case FN_CHECKPORT:
  1064.         return func_bool( (int)FindPort( av[0] ) );
  1065.     case FN_GETCLASS:
  1066.         if( str=getclass(av[0]) )
  1067.             if( str=index(strncpy( buf,str,100 ),0xA0) )
  1068.                 *str=0;
  1069.         return func_string(buf);
  1070.     case FN_COMPLETE:
  1071.         for( i=1, l=strlen(av[0]); i<ac; i++ )
  1072.             if( !Strncmp( av[0], av[i], l ) )
  1073.                 { str=av[i]; break; }
  1074.         return func_string( str );
  1075.     case FN_CONCAT:
  1076.         return func_string( compile_av( av, 0, ac, ' ', 1));
  1077.     case FN_CONFIRM:
  1078.         for( i=1, get++, confirmed=0; i<ac; i++ )
  1079.             if( confirm( av[0], av[i]) )
  1080.                 *get++=av[i];
  1081.         return func_array( av+1, (get-av)-1 );
  1082.     case FN_CONSOLE:
  1083.         if( !strcmp(av[0],"STDIN")) i=isconsole(Input());
  1084.         else if( !strcmp(av[0],"STDOUT")) i=isconsole(Output());
  1085.         return func_bool(i);
  1086.     case FN_DECTOHEX:
  1087.         sprintf( buf, "%x", unlatoi( av[0] ));
  1088.         return func_string( buf );
  1089.     case FN_DELWORDS:
  1090.         n2=posatoi( av[--ac] ); if( atoierr ) return 20;
  1091.     case FN_DELWORD:
  1092.         n=posatoi( av[--ac] )-1;
  1093.         for( ; i<ac && i<n; i++ ) *av++=*get++;
  1094.         for( ; i<ac && i<n+n2; i++ ) get++;
  1095.         for( ; i<ac ; i++ ) *av++=*get++;
  1096.         return func_array( oldav, av-oldav );
  1097.     case FN_DIRS:
  1098.         for( ; --ac>=0; get++ )
  1099.             if( exists( *get ) && isdir( *get ) )
  1100.                 *av++=*get;
  1101.         return func_array( oldav, av-oldav );
  1102.     case FN_DRIVE:
  1103.         return func_string( drive_name( av[0] ) );
  1104.     case FN_DRIVES:
  1105.         get_drives( buf );
  1106.         return func_string( buf );
  1107.     case FN_EXISTS:
  1108.         return func_bool( exists( av[0] ));
  1109.     case FN_FILEBLKS:
  1110.         return func_string( info_part( av, ac, 1, buf ) );
  1111.     case FN_FILELEN:
  1112.         while( --ac>=0 )
  1113.             i+=filesize( *av++ );
  1114.         return func_int( i );
  1115.     case FN_FILEPROT:
  1116.         return func_string( info_part( av, ac, 0, buf ) );
  1117.     case FN_FILEREQ:
  1118.         return func_string( file_request( av, ac, buf ) );
  1119.     case FN_FILES:
  1120.         for( ; --ac>=0; get++ )
  1121.             if( exists( *get ) && !isdir( *get ) )
  1122.                 *av++=*get;
  1123.         return func_array( oldav, av-oldav );
  1124.     case FN_FIRST:
  1125.         return func_string( av[0] );
  1126.     case FN_FREEBLKS:
  1127.         return func_string( oneinfo( av[0], 3 ));
  1128.     case FN_FREEBYTES:
  1129.         return func_string( oneinfo( av[0], 2 ));
  1130.     case FN_FREESTORE:
  1131.         return func_string( oneinfo( av[0], 4 ));
  1132.     case FN_HOWMANY:
  1133.         Getenv( shellctr, buf, 10);
  1134.         return func_string( buf );
  1135.     case FN_IOERROR:
  1136.         return func_string( ioerror( atoi( av[0] )));
  1137.     case FN_INDEX:
  1138.         str=strstr( av[0], av[1] );
  1139.         return func_int( str ? (str-av[0])+1 : 0 );
  1140.     case FN_INFO:
  1141.         return func_string( oneinfo( av[0], 1 ));
  1142.     case FN_INTERSECT:
  1143.         return wordset( av, ac, and );
  1144.     case FN_LAST:
  1145.         return func_string( ac ? av[ac-1] : "" );
  1146.     case FN_LOOKFOR:
  1147.         return func_string( dofind( av[0], "", buf, av[1]));
  1148.     case FN_LOWER:
  1149.         while( --ac>=0 ) strlwr( *av++ );
  1150.         return func_array( oldav, av-oldav );
  1151.     case FN_MATCH:
  1152.         for( str=av[--ac]; --ac>=0; get++ )
  1153.             if( compare_ok( str, *get, 0 ) )
  1154.                 *av++=*get;
  1155.         return func_array( oldav, av-oldav );
  1156.     case FN_MAX:
  1157.         for( n=MININT; i<ac; i++ ) 
  1158.             { if( (j=unlatoi(av[i] )) > n ) n=j; if( atoierr ) return 20; }
  1159.         return func_int( n );
  1160.     case FN_MEGS:
  1161.         return func_string( itok( atoi( av[0] )));
  1162.     case FN_MEMBER:
  1163.         for( i=1; i<ac && Strcmp(av[0],av[i]) ; i++ ) ;
  1164.         return func_bool( ac!=i );
  1165.     case FN_MIN:
  1166.         for( n=MAXINT; i<ac; i++ )
  1167.             { if( (j=unlatoi(av[i] )) < n ) n=j; if( atoierr ) return 20; }
  1168.         return func_int( n );
  1169.     case FN_MOUNTED:
  1170.         get=expand_devs();
  1171.         for( i=0; (str=get[i]) && Strcmp(str+1,av[0]); i++ ) ;
  1172.         free_expand(get);
  1173.         return func_bool((int)str);
  1174.     case FN_NAMEEXT:
  1175.         return func_string( rindex(av[0],'.')?rindex(av[0],'.')+1:(char *)NULL);
  1176.     case FN_NAMEROOT:
  1177.         if( rindex(av[0],'.') ) *rindex(av[0],'.')=0;
  1178.         return func_string( av[0] );
  1179.     case FN_PATHNAME:
  1180.         str=av[0]+strlen(av[0])-1;
  1181.         while( str>av[0] && *str!=':' && *str!='/' ) str--;
  1182.         if( *str==':' ) str++;
  1183.         *str=0;
  1184.         return func_string(av[0]);
  1185.     case FN_PICKARGS:
  1186.         while( *get && **get=='-' ) get++;
  1187.         while( *get )  *av++=*get++ ;
  1188.         return func_array( oldav, av-oldav );
  1189.     case FN_PICKOPTS:
  1190.         while( *get && **get=='-' ) *av++=*get++;
  1191.         return func_array( oldav, av-oldav );
  1192.     case FN_CLINUM:
  1193.         return func_int( clinum( av[0] ) );
  1194.     case FN_RPN:
  1195.         return func_int( eval_rpn( av, ac, 1 ));
  1196.     case FN_SORTARGS:
  1197.         QuickSort( av, ac );
  1198.         return func_array( av, ac );
  1199.     case FN_SORTNUM:
  1200.         DirQuickSort( av, ac, numcmp, 0, 0 );
  1201.         return func_array( av, ac );
  1202.     case FN_SPLIT:
  1203.         return split_arg( av, ac );
  1204.     case FN_STRCMP:
  1205.         return func_int( strcmp( av[0], av[1] ) );
  1206.     case FN_TRIM:
  1207.         for( ; *av; av++ ) {
  1208.             for( ; **av==' '; (*av)++ ) ;
  1209.             for( str=*av+strlen(*av); str>*av && str[-1]==' '; *--str=0 ) ;
  1210.         }
  1211.         return func_array( oldav, av-oldav );
  1212.     case FN_UNION:
  1213.         return wordset( av, ac, or );
  1214.     case FN_UNIQUE:
  1215.         QuickSort( av, ac );
  1216.         while( *get )
  1217.             { *av++=*get++; while( *get && !Strcmp(*get,*(get-1)))
  1218.                 get++; }
  1219.         return func_array( oldav, av-oldav );
  1220.     case FN_UPPER:
  1221.         while( --ac>=0 ) strupr( *av++ );
  1222.         return func_array( oldav, oldac );
  1223.     case FN_VOLUME:
  1224.         return func_string( oneinfo( av[0], 5 ));
  1225.     case FN_WINTOP:
  1226.         return func_int( Win ? Win->TopEdge : 0 );
  1227.     case FN_WINLEFT:
  1228.         return func_int( Win ? Win->LeftEdge: 0 );
  1229.     case FN_WINHEIGHT:
  1230.         return func_int( Win ? Win->Height : 0 );
  1231.     case FN_WINWIDTH:
  1232.         return func_int( Win ? Win->Width  : 0 );
  1233.     case FN_WORD:
  1234.         n2=1; goto wordf;
  1235.     case FN_SUBWORDS:
  1236.         n2=posatoi( av[--ac] ); if( atoierr ) return 20;
  1237.     wordf:
  1238.         n=posatoi( av[--ac] )-1; if( atoierr ) return 20;
  1239.         for( i=0; i<ac && i<n; i++ ) get++;
  1240.         for(    ; i<ac && i<n+n2; i++ ) *av++=*get++;;
  1241.         return func_array( oldav, av-oldav );
  1242.     case FN_WITHOUT:
  1243.         return wordset( av, ac, without );
  1244.     case FN_WORDS:
  1245.         return func_int( ac );
  1246.     }
  1247.     return func_string( "" );
  1248. }
  1249.